﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml;

namespace HSIA
{
    class LocateAPI
    {
        #region Google基站定位
        public static bool locate_GoogleGearsAPI(CellIDString cid, out double Lat, out double Lng)
        {
            HttpWebRequest request =
                (HttpWebRequest)WebRequest.Create("http://www.google.com/loc/json");
            request.Method = "POST";

            StringWriter StrWriter = new StringWriter();
            StrWriter.Write("{\n");
            StrWriter.Write("  \"version\": \"1.1.0\",\n");
            StrWriter.Write("  \"host\": \"maps.google.com\",\n");
            StrWriter.Write("  \"cell_towers\": [\n");
            StrWriter.Write("    {\n");
            StrWriter.Write("       \"cell_id\": {0},\n", cid.cellid);
            StrWriter.Write("       \"location_area_code\": {0},\n", cid.lac);
            //StrWriter.Write("       \"mobile_country_code\": {0},\n", cid.mcc);
            //StrWriter.Write("       \"mobile_network_code\": {0}\n", cid.mnc);
            StrWriter.Write("    }\n");
            StrWriter.Write("  ]\n");
            StrWriter.Write("}");

            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] byteArray = encoding.GetBytes(StrWriter.ToString());
            StrWriter.Close();

            // set request
            request.ContentLength = byteArray.Length;
            Stream postStream = request.GetRequestStream();
            postStream.Write(byteArray, 0, byteArray.Length);
            postStream.Close();

            // Get the response.
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Console.WriteLine("[I] Request response: {0}", response.StatusDescription);

            // Read response
            Stream dataStream = response.GetResponseStream();
            StreamReader readStream = new StreamReader(dataStream, Encoding.ASCII);
            string result = readStream.ReadToEnd();
            readStream.Close();
            dataStream.Close();
            response.Close();

            if (GetGearsAPI_Value(result, "\"latitude\":", out Lat)
                 && GetGearsAPI_Value(result, "\"longitude\":", out Lng))
                return true;

            Lat = 0;
            Lng = 0;
            return false;
        }

        public static bool locate_GoogleMapAPI(CellIDString cid, out double Lat, out double Lng)
        {
            HttpWebRequest request =
               (HttpWebRequest)WebRequest.Create("http://www.google.com/glm/mmap");
            request.Method = "POST";
            request.Timeout = 5000;
            // build request byte array
            byte[] byteArray = {0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
                        0x65, 0x6E, // en
                        0x00, 0x07,
                        0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, // Android
                        0x00, 0x03,
                        0x31, 0x2E, 0x30, // 1.0
                        0x00, 0x03,
                        0x57, 0x65, 0x62, // web
                        0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                        0x00,0x00,0x00,0x00,0x03,0x00,0x00,
                        0xFF, 0xFF, 0xFF, 0xFF, // CellID
                        0xFF, 0xFF, 0xFF, 0xFF, // LAC
                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };

            try
            {

                // write CellID
                byte[] intByte = BitConverter.GetBytes(System.Convert.ToInt32(cid.cellid));
                byteArray[48] = intByte[3];
                byteArray[49] = intByte[2];
                byteArray[50] = intByte[1];
                byteArray[51] = intByte[0];

                // write LAC
                intByte = BitConverter.GetBytes(System.Convert.ToInt32(cid.lac));
                byteArray[52] = intByte[3];
                byteArray[53] = intByte[2];
                byteArray[54] = intByte[1];
                byteArray[55] = intByte[0];

                // set request
                request.ContentLength = byteArray.Length;
                Stream postStream = request.GetRequestStream();
                postStream.Write(byteArray, 0, byteArray.Length);
                postStream.Close();

                // Get the response.
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Console.WriteLine("[I] Request response: {0}", response.StatusDescription);

                // Read response
                Stream dataStream = response.GetResponseStream();
                BinaryReader BR = new BinaryReader(dataStream);
                // skip 3 byte
                BR.ReadByte();
                BR.ReadByte();
                BR.ReadByte();

                // check state
                if (BR.ReadInt32() == 0)
                {
                    // read lat
                    byte[] tmpByte = new byte[4];
                    tmpByte[3] = BR.ReadByte();
                    tmpByte[2] = BR.ReadByte();
                    tmpByte[1] = BR.ReadByte();
                    tmpByte[0] = BR.ReadByte();
                    Lat = (double)(BitConverter.ToInt32(tmpByte, 0)) / 1000000D;

                    // read lng
                    tmpByte[3] = BR.ReadByte();
                    tmpByte[2] = BR.ReadByte();
                    tmpByte[1] = BR.ReadByte();
                    tmpByte[0] = BR.ReadByte();
                    Lng = (double)(BitConverter.ToInt32(tmpByte, 0)) / 1000000D;

                    BR.Close();
                    dataStream.Close();
                    response.Close();
                    return true;
                }
                else
                {
                    BR.Close();
                    dataStream.Close();
                    response.Close();
                    Lat = 0;
                    Lng = 0;
                    return false;
                }
            }
            catch (Exception)
            {
                Lat = 0;
                Lng = 0;
                return false;
            }

        }

        private static bool GetGearsAPI_Value(string Data, string TagName, out double value)
        {
            value = 0;

            int beginPos, endPos;
            beginPos = Data.IndexOf(TagName);
            if (beginPos == -1)
                return false;
            endPos = Data.IndexOf(',', beginPos);

            value = double.Parse(Data.Substring(beginPos + TagName.Length,
                                                endPos - beginPos - TagName.Length));
            return true;
        }

        #endregion

        #region 聚合基站定位
        private static List<GSMCell> listGSMCell = new List<GSMCell>();

        public static bool locate_JuHeAPI(CellIDString cid, out double Lat, out double Lng)
        {
            listGSMCell.Clear();
            string[] paramName = new string[5];
            string[] paramValue = new string[5];
            paramName[0] = "cell";
            paramName[1] = "lac";
            paramName[2] = "key";
            paramName[3] = "dtype";
            paramName[4] = "10";
            paramValue[0] = cid.cellid;
            paramValue[1] = cid.lac;
            paramValue[2] = "a78d3b41e67b6b6f6cdd4ba5779f3262";
            paramValue[3] = "xml";
            Lat = Lng = 0.0;
            string res = PostRequest("http://apis.juhe.cn/cell/get", paramName, paramValue);//http://apis.juhe.cn/cell/get
            if (parseGSMCellXML(res))
            {
                foreach (GSMCell gsmCell in listGSMCell)
                {
                    Lat = Convert.ToSingle(gsmCell.O_LAT);
                    Lng = Convert.ToSingle(gsmCell.O_LNG);
                }
                return true;
            }
            else return false;
        }

        private static bool parseGSMCellXML(string xml)
        {
            if (xml == "") return false;
            bool res = true;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);
            foreach (XmlNode xnf in xmlDoc.SelectSingleNode("root").ChildNodes)
            {
                XmlElement xe = (XmlElement)xnf;
                if (xe.Name.Equals("resultcode") && (int.Parse(xe.InnerText) != 200))
                {
                    res = false;
                }
                if (xe.Name.Equals("reason"))
                {
                    //this.textBoxMsg.Text = xe.InnerText;
                }
            }
            if (res)
            {
                foreach (XmlNode xnf in xmlDoc.SelectSingleNode("root/result/data").ChildNodes)
                {
                    XmlElement xe = (XmlElement)xnf;
                    XmlNodeList xnf1 = xe.ChildNodes;
                    GSMCell gsmCell = new GSMCell();
                    foreach (XmlNode xn2 in xnf1)
                    {
                        Console.WriteLine(xn2.InnerText);
                        if (xn2.Name.Equals("MCC"))
                        {
                            gsmCell.LAC = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("MNC"))
                        {
                            gsmCell.CELL = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("LNG"))
                        {
                            gsmCell.LNG = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("LAT"))
                        {
                            gsmCell.LAT = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("O_LNG"))
                        {
                            gsmCell.O_LNG = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("O_LAT"))
                        {
                            gsmCell.O_LAT = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("PRECISION"))
                        {
                            gsmCell.PRECISION = xn2.InnerText;
                        }
                        else if (xn2.Name.Equals("ADDRESS"))
                        {
                            gsmCell.ADDRESS = xn2.InnerText;
                        }
                    }
                    listGSMCell.Add(gsmCell);
                }
            }
            return res;
        }

        private static string PostRequest(string url, string[] paramName, string[] paramValue)
        {
            StringBuilder sbuilder = new StringBuilder(paramName[0] + "=" + paramValue[0]);
            for (int i = 1; i < paramName.Length; i++)
            {
                sbuilder.Append("&" + paramName[i] + "=" + paramValue[i]);
            }
            new ASCIIEncoding().GetBytes(sbuilder.ToString());
            string URL = url + "?" + sbuilder.ToString();
            try
            {
                Uri uri = new Uri(URL);
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                req.Timeout = 5000;
                HttpWebResponse wresp = (HttpWebResponse)req.GetResponse();
                StreamReader objReader = new StreamReader(wresp.GetResponseStream(), Encoding.GetEncoding("utf-8"));
                string result = objReader.ReadToEnd();
                objReader.Close();
                return result;
            }
            catch
            {
                return "";
            }
        }

        #endregion

    }

    class CellIDString
    {
        public string mcc;
        public string mnc;
        public string lac;
        public string cellid;
    }

    public class GSMCell
    {
        public string ADDRESS { get; set; }

        public string CELL { get; set; }

        public string LAC { get; set; }

        public string LAT { get; set; }

        public string LNG { get; set; }

        public string O_LAT { get; set; }

        public string O_LNG { get; set; }

        public string PRECISION { get; set; }
    }
}
